package sys_api

import (
	"fmt"
	"sync"
	"time"

	process2 "github.com/shirou/gopsutil/process"

	net2 "github.com/shirou/gopsutil/net"

	mem2 "github.com/shirou/gopsutil/mem"

	host2 "github.com/shirou/gopsutil/host"

	disk2 "github.com/shirou/gopsutil/disk"

	"github.com/gogf/gf/net/ghttp"

	cpu2 "github.com/shirou/gopsutil/cpu"
)

type processListReq struct {
}

type processListRes struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type cpuInfo struct {
	InfoStat cpu2.InfoStat `json:"infoStat"`
	Percent  float64       `json:"percent"`
	Cpu1     int           `json:"cpu1"`
	Cpu2     int           `json:"cpu2"`
}
type cpuTime struct {
	TimesStat cpu2.TimesStat `json:"timesStat"`
	Percent   float64        `json:"percent"`
}

type cpu struct {
	Info  cpuInfo   `json:"info"`
	Times []cpuTime `json:"times"`
}
type sysInfo struct {
	CPU     cpu     `json:"cpu"`
	Disk    disk    `json:"disk"`
	Host    host    `json:"host"`
	Mem     mem     `json:"mem"`
	Net     net     `json:"net"`
	Process process `json:"process"`
}

type disk struct {
	Partition []diskPartitionStat  `json:"partition"`
	IO        []diskIOCountersStat `json:"io"`
	Usage     []diskUsageStat      `json:"usage"`
}
type diskUsageStat struct {
	UsageStat *disk2.UsageStat
}
type diskPartitionStat struct {
	PartitionStat disk2.PartitionStat
}
type diskIOCountersStat struct {
	IOCountersStat disk2.IOCountersStat
}

type hostInfoStat struct {
	InfoStat *host2.InfoStat `json:"infoStat"`
}
type host struct {
	Info hostInfoStat `json:"info"`
}

type memSwapMemoryStat struct {
	SwapMemoryStat *mem2.SwapMemoryStat `json:"swapMemoryStat"`
}
type memVirtualMemoryStat struct {
	VirtualMemoryStat *mem2.VirtualMemoryStat `json:"virtualMemoryStat"`
}
type mem struct {
	SwapMemory    memSwapMemoryStat    `json:"swapMemory"`
	VirtualMemory memVirtualMemoryStat `json:"virtualMemory"`
}

type netIOCountersStat struct {
	IOCountersStat net2.IOCountersStat `json:"ioCountersStat"`
}
type netInterfaceStat struct {
	InterfaceStat net2.InterfaceStat `json:"interfaceStat"`
}
type net struct {
	IO    []netIOCountersStat `json:"io"`
	State []netInterfaceStat  `json:"state"`
}
type processt struct {
	Pid            int32                    `json:"pid"`
	Name           string                   `json:"name"`
	Status         string                   `json:"status"`
	CpuPercent     float64                  `json:"cpuPercent"`
	MemoryPercent  float32                  `json:"memoryPercent"`
	MemInfo        *process2.MemoryInfoStat `json:"memInfo"`
	NumThreads     int32                    `json:"numThreads"`
	CreateTime     int64                    `json:"createTime"`
	Children       []*process2.Process      `json:"children"`
	parent         int32
	parentMutex    *sync.RWMutex // for windows ppid cache
	numCtxSwitches *process2.NumCtxSwitchesStat
	uids           []int32
	gids           []int32
	groups         []int32

	sigInfo *process2.SignalInfoStat

	lastCPUTimes *cpu2.TimesStat
	lastCPUTime  time.Time
	tgid         int32
}
type process struct {
	Process []processt `json:"process"`
}

func (a *sysApi) ProcessList2(r *ghttp.Request) {
	var req *processListReq
	if err := r.Parse(&req); err != nil {
		r.Response.WriteJsonExit(processListRes{
			Code: 0,
			Msg:  err.Error(),
		})
	}
	var sysInfo sysInfo
	var wg sync.WaitGroup
	wg.Add(5)
	go func() {
		sysInfo.CPU = getCPU(&wg)
	}()
	go func() {
		sysInfo.Disk = getDisk(&wg)
	}()
	go func() {
		sysInfo.Host = getHost(&wg)
	}()
	go func() {
		sysInfo.Mem = getMem(&wg)
	}()
	go func() {
		sysInfo.Net = getNet(&wg)
	}()
	wg.Wait()
	fmt.Println(1)

	var processts []processt

	processes, _ := process2.Processes()
	for _, item := range processes {
		var processt processt
		processt.Pid = item.Pid
		processt.Name, _ = item.Name()
		processt.Status, _ = item.Status()
		processt.CpuPercent, _ = item.CPUPercent()
		processt.MemoryPercent, _ = item.MemoryPercent()
		processt.MemInfo, _ = item.MemoryInfo()
		processt.CreateTime, _ = item.CreateTime()
		processt.NumThreads, _ = item.NumThreads()
		processt.Children, _ = item.Children()
		processts = append(processts, processt)
		/*fmt.Println(item.Background())
		fmt.Println(item.CPUAffinity())		fmt.Println(item.Cmdline())
		fmt.Println(item.CmdlineSlice())
		fmt.Println(item.Connections())

		fmt.Println(item.Cwd())
		fmt.Println(item.Exe())
		fmt.Println(item.Foreground())
		fmt.Println(item.Gids())
		fmt.Println(item.Groups())
		fmt.Println(item.IOCounters())
		fmt.Println(item.IOnice())
		fmt.Println(item.IsRunning())


		fmt.Println(item.MemoryMaps(true))
		fmt.Println(item.MemoryMaps(false))

		fmt.Println(item.NetIOCounters(true))
		fmt.Println(item.NetIOCounters(false))
		fmt.Println(item.Nice())
		fmt.Println(item.NumFDs())

		fmt.Println(item.NumCtxSwitches())
		fmt.Println(item.OpenFiles())
		fmt.Println(item.PageFaults())
		fmt.Println(item.Parent())
		fmt.Println(item.Percent(time.Duration(200) * time.Millisecond))
		fmt.Println(item.Ppid())
		fmt.Println(item.Rlimit())

		fmt.Println(item.Terminal())
		fmt.Println(item.Tgid())
		fmt.Println(item.Threads())
		fmt.Println(item.Times())
		fmt.Println(item.Uids())
		fmt.Println(item.Username())
		fmt.Println(item.String())*/
	}
	var process process
	process.Process = processts
	sysInfo.Process = process
	fmt.Println(processts)
	//sysInfo.Disk = getDisk()

	r.Response.WriteJsonExit(processListRes{
		Code: 1,
		Data: sysInfo,
	})
}
func getNet(wg *sync.WaitGroup) net {
	defer wg.Done()
	var netInterfaceStats []netInterfaceStat
	interfaceStats, _ := net2.Interfaces()
	for _, item := range interfaceStats {
		var netInterfaceStat netInterfaceStat
		netInterfaceStat.InterfaceStat = item
		netInterfaceStats = append(netInterfaceStats, netInterfaceStat)
	}
	var netIOCountersStats []netIOCountersStat
	ioCounters, _ := net2.IOCounters(true)
	for _, item := range ioCounters {
		var netIOCountersStat netIOCountersStat
		netIOCountersStat.IOCountersStat = item
		netIOCountersStats = append(netIOCountersStats, netIOCountersStat)
	}
	ioCounters2, _ := net2.IOCounters(false)
	for _, item := range ioCounters2 {
		var netIOCountersStat netIOCountersStat
		netIOCountersStat.IOCountersStat = item
		netIOCountersStats = append(netIOCountersStats, netIOCountersStat)
	}

	var net net
	net.State = netInterfaceStats
	net.IO = netIOCountersStats
	return net
}

func getMem(wg *sync.WaitGroup) mem {
	defer wg.Done()
	var memSwapMemoryStat memSwapMemoryStat
	var memVirtualMemoryStat memVirtualMemoryStat
	memSwapMemoryStat.SwapMemoryStat, _ = mem2.SwapMemory()
	memVirtualMemoryStat.VirtualMemoryStat, _ = mem2.VirtualMemory()
	var mem mem
	mem.SwapMemory = memSwapMemoryStat
	mem.VirtualMemory = memVirtualMemoryStat
	return mem
}
func getHost(wg *sync.WaitGroup) host {
	defer wg.Done()
	var hostInfoStat hostInfoStat
	hostInfoStat.InfoStat, _ = host2.Info()
	var host host
	host.Info = hostInfoStat
	return host
}
func getCPU(wg *sync.WaitGroup) cpu {
	defer wg.Done()
	var cpuInfo1 cpuInfo
	infoStat, _ := cpu2.Info()
	cpuInfo1.InfoStat = infoStat[0]
	cpuInfo1.Percent = 0.1
	cpuInfo1.Cpu1, _ = cpu2.Counts(true)
	cpuInfo1.Cpu2, _ = cpu2.Counts(false)
	var cpu cpu
	cpu.Info = cpuInfo1

	//var cpuTimes []cpuTime
	cpuPercents, _ := cpu2.Percent(time.Duration(200)*time.Millisecond, true)
	cpuPercent, _ := cpu2.Percent(time.Duration(200)*time.Millisecond, false)
	cpuPercents = append(cpuPercents, cpuPercent...)
	cpuTime1, _ := cpu2.Times(true)
	cpuTime2, _ := cpu2.Times(false)
	cpuTime1 = append(cpuTime1, cpuTime2...)
	var cpuTimes []cpuTime
	for key, item := range cpuPercents {
		var cpuTime cpuTime
		cpuTime.TimesStat = cpuTime1[key]
		cpuTime.Percent = item
		cpuTimes = append(cpuTimes, cpuTime)
	}

	cpu.Times = cpuTimes

	return cpu
}

func getDisk(wg *sync.WaitGroup) disk {
	defer wg.Done()
	var disk disk
	var diskPartitionStats []diskPartitionStat
	var diskUsageStats []diskUsageStat
	Partitions, _ := disk2.Partitions(true)
	for _, item := range Partitions {
		var diskPartitionStat diskPartitionStat
		diskPartitionStat.PartitionStat = item
		diskPartitionStats = append(diskPartitionStats, diskPartitionStat)
		var diskUsageStat diskUsageStat
		diskUsageStat.UsageStat, _ = disk2.Usage(item.Device)
		diskUsageStats = append(diskUsageStats, diskUsageStat)

	}
	var diskIOCountersStats []diskIOCountersStat

	IOCounters, _ := disk2.IOCounters()
	for _, item := range IOCounters {
		var diskIOCountersStat diskIOCountersStat
		diskIOCountersStat.IOCountersStat = item
		diskIOCountersStats = append(diskIOCountersStats, diskIOCountersStat)
	}

	disk.Partition = diskPartitionStats
	disk.Usage = diskUsageStats
	disk.IO = diskIOCountersStats

	return disk
}
